<?php

declare(strict_types=1);

namespace Service\WebSocketService;

use Service\BaseService;
use Service\Code\Normal;
use Service\ExportService\ExportExcelHandle;
use App\Model\BbcModel\Goods;
use App\Model\BbcModel\GoodsClass;
use App\Model\BbcModel\GoodsBrand;
use App\Model\BbcModel\GoodsImportLog;
use App\Model\BbcModel\ManagerChannel;
use Service\CommodityService\ChannelCommodityEsService;
use Hyperf\DbConnection\Db;

/**
 * 渠道商品-商品资料导入修改
 * @author huj
 */
class ChannelCommodityDetailEditService extends BaseService
{
    const CHUNK_NUM = 50;
    
    /**
     * 商品资料导入修改
     * @param object $server
     * @param int $fd
     * @param array $body
     * @param int $manager_id
     * @param int $cid
     * 推送前端客户端方式
     * Normal::returnCode(Normal::WS_START,"开始处理");
     * Normal::returnCode(Normal::WS_END,"处理完成");
     * Normal::returnCode(Normal::WS_ERROR,"处理异常");
     * $server->push($fd,json_encode($result,JSON_UNESCAPED_UNICODE));
     */
    public function batchUpdate($server, int $fd, array $body, int $manager_id, int $cid) 
    {
        // $body = [
        //     'isUploadFile' => 1,
        //     'fileUrl'      => "https://indoorbuydev.oss-cn-hangzhou.aliyuncs.com/sbbc/channel/upload/修改商品资料模板_2023081016135035861.xlsx",
        //     'upLoadData'   => [
        //         ['2206211625251617', '橘酒子弹头11', '口红唇釉', "Benediktiner/百帝王", '0'],
        //         ['2205111130379904', '奶昔杯-121', '腮红', "sulwhasoo/雪花秀", '121'],
        //         ['2205111130378569', '奶昔杯-11', '腮红', "sulwhasoo/雪花秀1111", '12'],
        //     ],
        // ];
        if (!isset($body['isUploadFile']) || empty($body['isUploadFile'])) {
            return Normal::returnCode(Normal::WS_ERROR, '需上传文件');
        }
        if (!isset($body['fileUrl']) || empty($body['fileUrl'])) {
            return Normal::returnCode(Normal::WS_ERROR, '上传到oss的文件链接为空');
        }
        if (!isset($body['upLoadData']) || empty($body['upLoadData'])) {
            return Normal::returnCode(Normal::WS_ERROR, '上传的文件数据为空');
        }
        $originFileUrl  = $body['fileUrl'];
        $pathInfo       = pathinfo($originFileUrl);
        $originFileName = $pathInfo['filename'] ?? $pathInfo['basename'];
        $list           = $body['upLoadData'];
        $managerInfo    = $this->managerInfo($manager_id);
        //去除空行数据
        foreach ($list as $key => $item) {
            $checkCol = array_filter($item);
            if (empty($checkCol) || empty(reset($item))) {
                unset($list[$key]);
            }
        }
        $skuList       = array_filter(array_column($list, 0));
        $fields        = ['id', 'skucode', 'class_id', 'name', 'brand_id', 'show_order'];
        $allGoods      = Goods::whereIn('skucode', $skuList)->where('cid', $cid)->select($fields)->get()->toArray();
        $allGoodsBySku = array_column($allGoods, null, 'skucode');
        $allClass      = GoodsClass::where('cid', $cid)->pluck('id', 'name')->toArray();
        $alBrand       = GoodsBrand::where('cid', $cid)->pluck('id', 'name')->toArray();
        if ($server) {
            $send = Normal::returnCode(Normal::WS_START, "进行中", [
                'percent' => 5,
            ]);
            $server->push($fd, json_encode($send, JSON_UNESCAPED_UNICODE));
        }
        $errorData = [];
        $saveData  = [];
        $timeStp   = time();
        foreach ($list as $item) {
            $skuCode = $item[0];
            if (!isset($allGoodsBySku[$skuCode])) {
                array_push($item, '自编码对应商品不存在');
                $errorData[] = $item;
                continue;
            }
            if (!isset($allClass[$item[2]])) {
                array_push($item, '分类不存在');
                $errorData[] = $item;
                continue;
            }
            if (!isset($alBrand[$item[3]])) {
                array_push($item, '品牌不存在');
                $errorData[] = $item;
                continue;
            }
            if (!is_numeric($item[4])) {
                $item[4] = false;
            } else {
                $res1 = $this->regex($item[4], '/^\d+$/');
                if (!$res1) {
                    array_push($item, '排序值为纯数字');
                    $errorData[] = $item;
                    continue;
                }
            }
            $row     = $allGoodsBySku[$skuCode];
            $rowData = [
                'id'       => $row['id'],
                'name'     => $item[1],
                'class_id' => $allClass[$item[2]],
                'brand_id' => $alBrand[$item[3]],
                'md'       => $timeStp
            ];
            if ($item[4] === false) {
                $rowData['show_order'] = $row['show_order'];
            } else {
                $rowData['show_order'] = (int)$item[4];
            }
            $saveData[] = $rowData;
        }
        if (!empty($errorData)) {
            $fileName  = "商品资料导入修改错误信息.xlsx";
            $headArr   = $this->getColumns();
            $exportRes = ExportExcelHandle::instance()->uploadAliOssSource($fileName, $headArr, $errorData);
            if ($exportRes['code'] != Normal::SUC) {
                return Normal::returnCode(Normal::WS_ERROR, $exportRes['msg'] ?? '生成商品资料导入修改错误信息失败');
            }
            $download_url = $exportRes['data']['path'];
        }
        if ($server) {
            $send = Normal::returnCode(Normal::WS_START, "进行中", [
                'percent' => 10,
            ]);
            $server->push($fd, json_encode($send, JSON_UNESCAPED_UNICODE));
        }
        $count = count($saveData);
        if ($count == 0) {
            //保存到导入日志
            $importLog = [
                'cid'             => $cid,
                'file_name'       => $originFileName,
                'import_type'     => 1,
                'all_num'         => count($list),
                'success_num'     => $count,
                'fail_num'        => count($errorData),
                'status'          => count($errorData) > 0 ? 2 : 1,
                'origin_file_url' => $originFileUrl,
                'fail_file_url'   => $download_url ?? '',
                'manager_id'      => $manager_id,
                'manager_name'    => $managerInfo['name'],
                'cd'              => $timeStp,
                'md'              => $timeStp,
            ];
            GoodsImportLog::insert($importLog);
            if ($server) {
                $send = Normal::returnCode(Normal::WS_END, "已完成", [
                    'percent'      => 100,
                    'download_url' => $download_url ?? '',
                ]);
                $server->push($fd, json_encode($send, JSON_UNESCAPED_UNICODE));
            }
        }
        $newSaveData = array_column($saveData, null, 'id');
        $chunkData   = array_chunk($newSaveData, self::CHUNK_NUM);
        $percent     = 10.00;
        foreach ($chunkData as $k => $upData) {
            $sqlArr = $this->mergeSql($upData);
            //执行批量更新
            $updateSqlStr  = implode(",", $sqlArr['updateSql']);
            $whereIds      = implode(",", $sqlArr['ids']);
            $databaseName  = Goods::instance()->getConnection()->getDatabaseName();
            $tableName     = Goods::instance()->getTable();
            $sql_batch_sql = "UPDATE `{$databaseName}`.`{$tableName}` SET {$updateSqlStr} WHERE ID IN({$whereIds})";
            Db::connection('bbc_commodity')->update($sql_batch_sql);
            //更新es索引
            ChannelCommodityEsService::instance()->updateIndexByBatchGoods($sqlArr['ids'], $cid);

            $per        = bcdiv((string)($k + 1), (string)$count, 4);
            $currentPer = bcmul(bcmul($per, '100', 2), '0.88', 2);
            $pushPer    = bcadd($currentPer, (string)$percent, 2);
            if ($server) {
                $send = Normal::returnCode(Normal::WS_START, "进行中", [
                    'percent' => $pushPer,
                ]);
                $server->push($fd, json_encode($send, JSON_UNESCAPED_UNICODE));
            }
        }
        //保存到导入日志
        $importLog = [
            'cid'             => $cid,
            'file_name'       => $originFileName,
            'import_type'     => 1,
            'all_num'         => count($list),
            'success_num'     => $count,
            'fail_num'        => count($errorData),
            'status'          => count($errorData) > 0 ? 2 : 1,
            'origin_file_url' => $originFileUrl,
            'fail_file_url'   => $download_url ?? '',
            'manager_id'      => $manager_id,
            'manager_name'    => $managerInfo['name'],
            'cd'              => $timeStp,
            'md'              => $timeStp,
        ];
        GoodsImportLog::insert($importLog);
        return Normal::returnCode(Normal::WS_END, "已完成", [
            'percent'      => 100.00,
            'download_url' => $download_url ?? '',
        ]);

    }

    /**
     * 组装批量更新的SQL 语句
     * @param [type] $upData
     * @return array
     * @author huj
     * @DateTime 2022-04-01 09:54:44
     */
    public function mergeSql($upData) {
        //需要更新的字段
        $updateSqlColumns = [
            'name',
            'class_id',
            'brand_id',
            'md',
            'show_order'
        ];
        $when             = [];
        foreach ($upData as $v1) {
            foreach ($updateSqlColumns as $column) {
                $then            = $v1[$column];
                $when[$column][] = "WHEN {$v1['id']} THEN '{$then}'";
            }
        }
        $updateSql = [];
        foreach ($updateSqlColumns as $column) {
            $updateSql[] = "{$column} = CASE id " . (implode(" ", $when[$column])) . " END";
        }
        return [
            'ids'       => array_column($upData, 'id'),
            'updateSql' => $updateSql,
        ];
    }

    //excel头部
    public function getColumns() {
        return ['sku', '商品名称', '商品分类', '品牌', 'b2b排序值（非必填）', '错误信息'];
    }

    /**
     * 获取后台操作人员信息
     */
    public function managerInfo($manager_id) {
        return ManagerChannel::instance()->info(['id' => $manager_id]);
    }

    /**
     * 使用正则验证数据
     * @access public
     * @param mixed $value 字段值
     * @param mixed $rule 验证规则 正则规则或者预定义正则名
     * @return bool
     */
    protected function regex($value, $rule) {
        return is_scalar($value) && 1 === preg_match($rule, (string)$value);
    }

}